/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file    usart.c
 * @brief   USART串口通信模块实现文件
 *          包含USART1初始化、中断处理、数据解析和命令响应功能
 * @author  STMicroelectronics
 * @date    2025
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2025 STMicroelectronics.
 * All rights reserved.
 *
 * 此软件依据位于该软件组件根目录下的LICENSE文件中的条款进行许可。
 * 如果该软件没有附带LICENSE文件，则按“原样”提供。
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */
#include "KEY.h"
#include "main.h"
#include "tim.h"
#include "LedCtrl.h"
#include <string.h> 
// 外部变量声明 - 来自main.c的串口接收缓冲区
extern uint8_t USART_RX_Buffer[USART_RX_BUFFER_SIZE];
// 外部变量声明 - 来自main.c的接收缓冲区索引(volatile确保多线程可见性)
extern volatile uint8_t USART_RX_Index;

// 添加学习模式相关全局变量
uint8_t studyModeActive = 0;        // 学习模式激活标志
uint32_t studyModeRemainingTime = 0; // 学习模式剩余时间(秒)
#define STUDY_MODE_DURATION 2400     // 学习模式持续时间(40分钟 = 2400秒)

/**
 * @brief 预设的串口命令帧定义
 * @details 共8组命令帧，每组9字节，格式为：
 *          [0x7E起始符][长度][设备地址][命令][数据1][数据2][校验和][0xEF结束符]
 */
const uint8_t serialDataFrames[8][9] = {
    {0x7E,0x07,0xFF,0x06,0xA0,0x00,0x0F,0xBB,0xEF},
    {0x7E,0x07,0xFF,0x06,0xA0,0x00,0x10,0xBC,0xEF},
    {0x7E,0x07,0xFF,0x06,0xA0,0x00,0x11,0xBD,0xEF},
    {0x7E,0x07,0xFF,0x06,0xA0,0x00,0x12,0xBE,0xEF},
    {0x7E,0x07,0xFF,0x06,0xA0,0x00,0x13,0xBF,0xEF},
    {0x7E,0x07,0xFF,0x06,0xA0,0x00,0x14,0xC0,0xEF},
    {0x7E,0x07,0xFF,0x06,0xA0,0x00,0x15,0xC1,0xEF},
    {0x7E,0x07,0xFF,0x06,0xA0,0x00,0x16,0xC2,0xEF},
};

/**
 * @brief 根据索引发送预设的串口命令帧
 * @param index 命令帧索引(0-7)，超出范围将不发送
 * @note 发送指定索引的预设命令帧到USART1
 */
void SendSerialDataByIndex(uint8_t index) {
    if (index < 8) {  // 检查索引有效性(0-7)
        HAL_UART_Transmit(&huart1, serialDataFrames[index], 9, 100);    
    }
}

/**
 * @brief TIM3中断处理函数
 * @note 用于学习模式的计时功能，每秒递减剩余时间
 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM3 && studyModeActive)
    {
        // TIM3配置为1ms中断一次，这里每1000次中断为1秒
        static uint16_t count = 0;
        count++;
        
        if (count >= 1000)
        {
            count = 0;
            studyModeRemainingTime--;
            
            // 学习模式时间结束
            if (studyModeRemainingTime <= 0)
            {
                studyModeActive = 0;
                // 发送学习模式结束命令
                SendSerialDataByIndex(1); // 这里使用索引1的命令帧作为结束指令
            }
        }
    }
}
/* USER CODE END 0 */

UART_HandleTypeDef huart1;

/* USART1 init function */

/**
 * @brief USART1串口初始化函数
 * @param 无
 * @retval 无
 * @note 配置USART1的波特率、数据位、停止位、校验位等参数
 */
void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 9600;            // 波特率设置为9600
  huart1.Init.WordLength = UART_WORDLENGTH_8B;  // 8位数据位
  huart1.Init.StopBits = UART_STOPBITS_1;      // 1位停止位
  huart1.Init.Parity = UART_PARITY_NONE;       // 无校验位
  huart1.Init.Mode = UART_MODE_TX_RX;          // 收发模式
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 无硬件流控
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;  // 16倍采样
  huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;  // 禁止1位采样
  huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;  // 不使用高级功能
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
 * @brief UART底层硬件初始化函数
 * @param uartHandle UART句柄结构体指针
 * @retval 无
 * @note 配置UART相关的GPIO引脚、时钟和中断
 */
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* USART1时钟使能 */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**USART1 GPIO配置
    PB6     ------> USART1_TX
    PB7     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;     // 复用推挽输出
    GPIO_InitStruct.Pull = GPIO_NOPULL;         // 无上下拉
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;  // 高速
    GPIO_InitStruct.Alternate = GPIO_AF0_USART1;   // 复用为USART1
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* USART1中断初始化 */
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);  // 设置中断优先级
    HAL_NVIC_EnableIRQ(USART1_IRQn);          // 使能中断
  /* USER CODE BEGIN USART1_MspInit 1 */

  /* USER CODE END USART1_MspInit 1 */
  }
}

/**
 * @brief UART底层硬件反初始化函数
 * @param uartHandle UART句柄结构体指针
 * @retval 无
 * @note 禁用UART相关的GPIO引脚、时钟和中断
 */
void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */

  /* USER CODE END USART1_MspDeInit 0 */
    /* 禁用外设时钟 */
    __HAL_RCC_USART1_CLK_DISABLE();

    /**USART1 GPIO配置
    PB6     ------> USART1_TX
    PB7     ------> USART1_RX
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6|GPIO_PIN_7);

    /* 禁用USART1中断 */
    HAL_NVIC_DisableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspDeInit 1 */

  /* USER CODE END USART1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
/**
 * @brief UART接收完成回调函数
 * @param huart UART句柄结构体指针
 * @retval 无
 * @note 当UART接收中断触发并完成一个字节接收后调用
 *       负责实现循环接收缓冲和数据帧校验功能
 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  // 检查中断来源是否为USART1
  if (huart->Instance == USART1)
  {
    // 接收索引自增
    USART_RX_Index++;

    // 检查接收缓冲区是否溢出(循环覆盖)
    if (USART_RX_Index >= USART_RX_BUFFER_SIZE)
    {
      USART_RX_Index = 0;
    }

    // 当接收数据达到8字节(一帧)时进行处理
    if (USART_RX_Index >= 8)
    {
      // 校验帧头帧尾和长度(简化校验)
      for (int i = 0; i < 8; i++)
      {
        // 检查帧头(0x7E)和帧长度(0x06)
        if (USART_RX_Buffer[i] != 0x7E || USART_RX_Buffer[i + 1] != 0x06)
        {
          // 校验失败，清空缓冲区
          memset(USART_RX_Buffer, 0, sizeof(USART_RX_Buffer));
          USART_RX_Index = 0;
          break;
        }
        else
        {
          // 校验通过，解析命令帧
          ParseIdentificationCode(USART_RX_Buffer);
          // 清空缓冲区准备下次接收
          memset(USART_RX_Buffer, 0, sizeof(USART_RX_Buffer));
          USART_RX_Index = 0;
          break;
        }
      }
    }

    // 重新启动UART中断接收(接收下一个字节)
    HAL_UART_Receive_IT(&huart1, (uint8_t *)&USART_RX_Buffer[USART_RX_Index], 1);
  }
}

/**
 * @brief 串口命令帧解析函数
 * @param buffer 接收到的命令帧缓冲区(8字节)
 * @retval 无
 * @note 实现对不同命令帧的解析和相应的设备控制逻辑
 *       支持电源开关、亮度调节、模式切换等功能
 */
void ParseIdentificationCode(uint8_t *buffer)
{
  // 校验帧头(0x7E)、帧尾(0xEF)和地址(0xFF)
  if (buffer[0] == 0x7E && buffer[1] == 0x06 && buffer[2] == 0xFF && buffer[7] == 0xEF)
  {
    uint8_t command = buffer[3];    // 命令字节(第4字节)
    uint8_t data1 = buffer[4];      // 数据1字节(第5字节)
    uint8_t data2 = buffer[5];      // 数据2字节(第6字节)
    

    // 根据命令字节执行相应操作
    switch (command)
    {
    case 0x06:  // 设备控制命令
      // 电源开启命令(data1=0x01, data2=0x03或0x04)
      if (data1 == 0x01 && (data2 == 0x03||data2 == 0x04))
      {
        // 检查当前电源状态，仅在关闭时执行开启
        if (DeviceStatus.powerState == 0)
        {
          DeviceStatus.powerState = 1;        // 设置电源状态为开启
          DeviceStatus.pendingLevel = 1;      // 设置待生效亮度等级为1
          DeviceStatus.pendingMode = 0;       // 设置待生效模式为0
          LEDParameterSET.LEDRATIO = 1.0;     // 设置LED比例参数
          SendSerialDataByIndex(2);           // 发送电压响应帧(索引2)
          
          // 电源开启时，如果学习模式之前是激活的，重新启动计时
          if (studyModeActive)
          {
              studyModeRemainingTime = STUDY_MODE_DURATION;
          }
        }
      }
      // 电源关闭命令(data1=0x01, data2=0x0E或0x0F)
      else if (data1 == 0x01 && (data2 == 0x0E||data2 == 0x0F))
      {
        // 检查当前电源状态，仅在开启时执行关闭
        if (DeviceStatus.powerState == 1)
        {
          DeviceStatus.powerState = 0;        // 设置电源状态为关闭
          DeviceStatus.pendingLevel = 0;      // 设置待生效亮度等级为0
          DeviceStatus.pendingMode = 0;       // 设置待生效模式为0
          LEDParameterSET.LEDRATIO = 1.0;     // 设置LED比例参数
          SendSerialDataByIndex(3);           // 发送温度响应帧(索引3)
        }
        
      }
      // 亮度最大命令(data1=0x01, data2=0x05或0x09或0x0B)
      else if (data1 == 0x01 && (data2 == 0x05||data2 == 0x09||data2 == 0x0B))
      {
        // 仅在电源开启时执行
        if (DeviceStatus.powerState == 1)
        {
          DeviceStatus.pendingLevel = 3;      // 设置亮度等级为3(高亮度)
          SendSerialDataByIndex(4);           // 发送温度响应帧(索引4)
          LEDParameterSET.LEDRATIO = 1.0;     // 设置LED比例参数
        }
        
      }
      // 亮度最小命令(data1=0x01, data2=0x06或0x0A或0x0C)
      else if (data1 == 0x01 && (data2 == 0x06||data2 == 0x0A||data2 == 0x0C))
      {
        if (DeviceStatus.powerState == 1)
        {
          DeviceStatus.pendingLevel = 1;      // 设置亮度等级为1(低亮度)
          SendSerialDataByIndex(5);           // 发送帮助信息帧(索引5)
          LEDParameterSET.LEDRATIO = 1.0;     // 设置LED比例参数
        }
        
      }
      
      // 增加LED比例命令(data1=0x01, data2=0x07)
      else if (data1 == 0x01 && data2 == 0x07)
      {
        if (DeviceStatus.powerState == 1)
        {
          // 根据当前模式设置PWM比较值(4000K色温)
          if (LEDParameterSET.LEDRATIO <= 1.3){
            LEDParameterSET.LEDRATIO = LEDParameterSET.LEDRATIO + 0.1;  // 增加LED比例
            SendSerialDataByIndex(6);           // 发送帮助已发送帧(索引6)
          }
          
        }
      }
      // 减少LED比例命令(data1=0x01, data2=0x08)
      else if (data1 == 0x01 && data2 == 0x08)
      {
        if (DeviceStatus.powerState == 1)
        {
          // 根据当前模式设置PWM比较值(4000K色温)
          if (LEDParameterSET.LEDRATIO >= 0.7){
            LEDParameterSET.LEDRATIO = LEDParameterSET.LEDRATIO - 0.1;  // 减少LED比例
            SendSerialDataByIndex(7);           // 发送帮助已发送帧(索引7)  
          }
        }
      }
      // 学习模式命令(data1=0x01, data2=0x0D)
      else if (data1 == 0x01 && data2 == 0x0D)
      {
        SendSerialDataByIndex(0);  // 发送学习模式响应帧(索引0)
        
        // 启动学习模式计时
        if (DeviceStatus.powerState == 1)
        {
            studyModeActive = 1;                  // 激活学习模式
            studyModeRemainingTime = STUDY_MODE_DURATION; // 设置40分钟(2400秒)计时
            
            // 确保TIM3已经启动并开启中断
            HAL_TIM_Base_Start_IT(&htim3);
        }
      }
      break;
      // 可添加其他命令的处理分支
    }
  }
  else
  {
    // 帧格式校验失败，清空缓冲区
    memset(USART_RX_Buffer, 0, sizeof(USART_RX_Buffer));
    USART_RX_Index = 0;
  }
}

/* USER CODE END 1 */